package xyz.redtorch.client.strategy;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import xyz.redtorch.client.service.ClientTradeCacheService;
import xyz.redtorch.client.service.rpc.RpcClientApiService;
import xyz.redtorch.common.util.UUIDStringPoolUtils;
import xyz.redtorch.config.SpringContextUtil;
import xyz.redtorch.pb.CoreEnum.ContingentConditionEnum;
import xyz.redtorch.pb.CoreEnum.DirectionEnum;
import xyz.redtorch.pb.CoreEnum.ForceCloseReasonEnum;
import xyz.redtorch.pb.CoreEnum.HedgeFlagEnum;
import xyz.redtorch.pb.CoreEnum.OffsetFlagEnum;
import xyz.redtorch.pb.CoreEnum.OrderPriceTypeEnum;
import xyz.redtorch.pb.CoreEnum.TimeConditionEnum;
import xyz.redtorch.pb.CoreEnum.VolumeConditionEnum;
import xyz.redtorch.pb.CoreField.AccountField;
import xyz.redtorch.pb.CoreField.CancelOrderReqField;
import xyz.redtorch.pb.CoreField.ContractField;
import xyz.redtorch.pb.CoreField.OrderField;
import xyz.redtorch.pb.CoreField.SubmitOrderReqField;
import xyz.redtorch.pb.CoreField.TickField;
import xyz.redtorch.pb.CoreField.TradeField;

public abstract class StrategyTemplate {

	private static final Logger logger = LoggerFactory.getLogger(StrategyEngineServiceImpl.class);

	protected boolean initSwitch;
	protected boolean tradingSwitch;
	protected String strategyId;
	protected Set<String> subscribedUnifiedSymbolSet = new HashSet<>();
	protected Set<String> originOrderIdSet = new HashSet<>();

	protected ClientTradeCacheService clientTradeCacheService = SpringContextUtil
			.getBean(ClientTradeCacheService.class);
	protected RpcClientApiService rpcClientApiService = SpringContextUtil.getBean(RpcClientApiService.class);

	protected StrategyTemplate(String strategyId) {
		this.strategyId = strategyId;
	}

	public String getStrategyId() {
		return strategyId;
	}

	public Set<String> getSubscribedUnifiedSymbolSet() {
		return subscribedUnifiedSymbolSet;
	}

	public Set<String> getOriginOrderIdSet() {
		return originOrderIdSet;
	}

	public void initStrategy() {
		if (!initSwitch) {
			try {
				onInit();
				initSwitch = true;
			} catch (Exception e) {
				logger.error("策略{}初始化异常 ", strategyId, e);
			}
		} else {
			logger.warn("策略{}已经初始化,请勿重复初始化", strategyId);
		}
	}

	public void startTrading() {
		if (!initSwitch) {
			logger.error("策略{}尚未初始化,请首先初始化", strategyId);
			return;
		}
		if (!tradingSwitch) {
			try {
				onStartTrading();
				tradingSwitch = true;
			} catch (Exception e) {
				logger.error("策略{}启动异常", strategyId);
			}
		} else {
			logger.warn("策略{}已经处于交易状态", strategyId);
		}
	}

	public void stopTrading(boolean finishedCorrectly) {
		if (tradingSwitch) {
			tradingSwitch = false;
			try {
				onStopTrading(finishedCorrectly);
			} catch (Exception e) {
				logger.error("策略{}停止异常", strategyId);
			}
		}
	}

	protected void processTick(TickField tick) {
		if (initSwitch && tradingSwitch) {
			try {
				onTick(tick);
			} catch (Exception e) {
				stopTrading(false);
				logger.error("策略{}处理Tick异常", strategyId);
			}
		}
	}

	protected void processTrade(TradeField trade) {
		if (initSwitch && tradingSwitch) {
			try {
				onTrade(trade);
			} catch (Exception e) {
				stopTrading(false);
				logger.error("策略{}处理Trade异常", strategyId);

			}
		}
	}

	protected void processOrder(OrderField order) {
		if (initSwitch && tradingSwitch) {
			try {
				onOrder(order);
			} catch (Exception e) {
				stopTrading(false);
				logger.error("策略{}处理Order异常", strategyId);
			}
		}
	}

	protected void onInit() {
		logger.warn("策略{}初始化", strategyId);
	}

	protected void onStartTrading() {
		logger.warn("策略{}开始交易", strategyId);
	}

	protected void onStopTrading(boolean finishedCorrectly) {
		logger.warn("策略{}停止交易, {}", strategyId, finishedCorrectly);
	}

	protected void onTick(TickField tick) {
		// 已经根据订阅过滤了不属于此策略的行情
		logger.info("策略{}收tick \n {}", strategyId, tick);
	}

	protected void onTrade(TradeField trade) {
		// 校验是否是策略发出的定单
		if (originOrderIdSet.contains(trade.getOriginOrderId())) {
			logger.info("策略{}收trade \n {}", strategyId, trade);
		}
	}

	protected void onOrder(OrderField order) {
		// 校验是否是策略发出的定单
		if (originOrderIdSet.contains(order.getOriginOrderId())) {
			logger.info("策略{}收order \n {}", strategyId, order);
		}
	}

	protected String submitOrder(String unifiedSymbol, OrderPriceTypeEnum orderPriceType, DirectionEnum direction,
			OffsetFlagEnum offsetFlag, String accountId, double price, int volume, String originOrderId, boolean sync) {
		if (initSwitch && tradingSwitch) {
			SubmitOrderReqField.Builder submitOrderReqFieldBuilder = SubmitOrderReqField.newBuilder();

			ContractField contract = clientTradeCacheService.getMixContractDict().get(unifiedSymbol);
			submitOrderReqFieldBuilder.setContract(contract);
			submitOrderReqFieldBuilder.setDirection(direction);
			submitOrderReqFieldBuilder.setOffsetFlag(offsetFlag);
			submitOrderReqFieldBuilder.setOrderPriceType(orderPriceType);
			submitOrderReqFieldBuilder.setTimeCondition(TimeConditionEnum.TC_GFD);
			submitOrderReqFieldBuilder.setPrice(price);
			submitOrderReqFieldBuilder.setMinVolume(1);
			submitOrderReqFieldBuilder.setStopPrice(0.0);
			submitOrderReqFieldBuilder.setVolumeCondition(VolumeConditionEnum.VC_AV);
			submitOrderReqFieldBuilder.setContingentCondition(ContingentConditionEnum.CC_Immediately);
			submitOrderReqFieldBuilder.setHedgeFlag(HedgeFlagEnum.HF_Speculation);
			submitOrderReqFieldBuilder.setForceCloseReason(ForceCloseReasonEnum.FCR_NotForceClose);
			submitOrderReqFieldBuilder.setVolume(volume);
			AccountField account = clientTradeCacheService.getAccountDict().get(accountId);
			submitOrderReqFieldBuilder.setGatewayId(account.getGatewayId());
			submitOrderReqFieldBuilder.setAccountCode(account.getCode());
			submitOrderReqFieldBuilder.setCurrency(account.getCurrency());

			if (StringUtils.isBlank(originOrderId)) {
				submitOrderReqFieldBuilder.setOriginOrderId(UUIDStringPoolUtils.getUUIDString());
			} else {
				submitOrderReqFieldBuilder.setOriginOrderId(originOrderId);
			}

			originOrderIdSet.add(submitOrderReqFieldBuilder.getOriginOrderId());
			SubmitOrderReqField submitOrderReqField = submitOrderReqFieldBuilder.build();

			logger.warn("策略{}提交定单 \n {}", strategyId, submitOrderReqFieldBuilder);
			if (sync) {
				String orderId = rpcClientApiService.submitOrder(submitOrderReqField,
						UUIDStringPoolUtils.getUUIDString(), 5);
				return orderId;
			} else {
				rpcClientApiService.asyncSubmitOrder(submitOrderReqField, UUIDStringPoolUtils.getUUIDString());
				return null;
			}
		} else {
			logger.error("策略尚未初始化或未处于交易状态");
			return null;
		}
	}
	
	protected boolean asyncCancelOrder(String orderId, String originOrderId, String reqId) {
		CancelOrderReqField.Builder cancelOrderReqField = CancelOrderReqField.newBuilder();
		cancelOrderReqField.setOrderId(orderId);
		cancelOrderReqField.setOriginOrderId(originOrderId);
		return rpcClientApiService.asyncCancelOrder(cancelOrderReqField.build(), reqId);
	}

	protected boolean cancelOrder(String orderId, String originOrderId, String reqId, boolean sync) {
		CancelOrderReqField.Builder cancelOrderReqField = CancelOrderReqField.newBuilder();
		cancelOrderReqField.setOrderId(orderId);
		cancelOrderReqField.setOriginOrderId(originOrderId);
		if (sync) {
			return rpcClientApiService.cancelOrder(cancelOrderReqField.build(), reqId, 5);
		} else {
			return asyncCancelOrder(orderId, originOrderId, reqId);
		}
	}

	protected void subscribe(String unifiedSymbol, String gatewayId) {
		if (clientTradeCacheService.getMixContractDict().containsKey(unifiedSymbol)) {
			subscribedUnifiedSymbolSet.add(unifiedSymbol);
			ContractField contract = clientTradeCacheService.getMixContractDict().get(unifiedSymbol);
			ContractField.Builder newBuilder = ContractField.newBuilder(contract);
			if (!StringUtils.isBlank(gatewayId)) {
				newBuilder.setGatewayId(gatewayId);
			} else {
				newBuilder.setGatewayId("");
			}
			ContractField contractField = newBuilder.build();
			clientTradeCacheService.storeContract(contractField);
			rpcClientApiService.subscribe(clientTradeCacheService.getMixContractDict().get(unifiedSymbol),
					UUIDStringPoolUtils.getUUIDString(), 5);
		} else {
			logger.error("策略{}订阅行情错误,未能找到合约{}", strategyId, unifiedSymbol);
		}
	}

	protected void unsubscribe(String unifiedSymbol, String gatewayId) {
		if (clientTradeCacheService.getMixContractDict().containsKey(unifiedSymbol)) {
			subscribedUnifiedSymbolSet.add(unifiedSymbol);
			rpcClientApiService.unsubscribe(clientTradeCacheService.getMixContractDict().get(unifiedSymbol), gatewayId,
					5);
		} else {
			logger.error("策略{}退订行情错误,未能找到合约{}", strategyId, unifiedSymbol);
		}
	}

}
